package Server;
import Server.Tasks.*;
import java.net.*;
import java.util.LinkedList;
import java.util.Queue;
import java.io.*;

import Server.Tasks.PhoneTask;
import Server.Tasks.ServerTask;

public class PhoneServerThread extends Thread {
	public enum States {
		IDLE,
		WAITING,
		RINGING,
		OFF_HOOK,
		IN_CALL,
		NO_CALL
	}
	
	public enum Status {
		ACTIVATED,
		DEACTIVATED,
		CANNOT_CALL,
		CANNOT_RECEIVE
	}
	
	private States state;
	private Status status;
	
    private Socket socket = null;
    private PhoneServer server = null;
    
    private Queue<PhoneTask> messageList = new LinkedList<PhoneTask>();
    
    private String phoneName;
    private int extension;
    private Call currentCall;
    
    private boolean hwTest = false;
    private long hwTestTimer = 0;
    
    
    public PhoneServerThread(Socket socket, PhoneServer server) {
    	super("PhoneServerThread");
    	this.socket = socket;
    	this.server = server;
    }

    public void run() {

    	PrintWriter out = null;
    	BufferedReader in = null;
    	
		try {
		    out = new PrintWriter(socket.getOutputStream(), true);
		    in = new BufferedReader(
					    new InputStreamReader(
					    socket.getInputStream()));
	
		    String inputLine, outputLine;
		    String[] p; 
	    	PhoneTask t;
	    	
	    	state = States.IDLE;
	    	status = Status.DEACTIVATED;
	    	                            
	    	
	    	
		    while (!socket.isClosed()) {
				//outputLine = kkp.processInput(inputLine);
		    	
		    	if (in.ready()) {
		    		inputLine = in.readLine();
		    		System.out.println("Received message: " + inputLine);
		    		
		    		if (inputLine.equals("Bye"))			
					    break;
		    		
		    		p = inputLine.split(":");
	    			if(p[0].equals("Name")) {
			    		server.addMessage(new NewPhoneTask(this, 2, p[1], server));
	    			} else if(p[0].equals("Call")) {
	    				server.addMessage(new CallTask(this, 5, p[1], server));
	    			} else if(p[0].equals("OffHook")) {
	    				if(state == States.IDLE) {
		    				if((status == Status.ACTIVATED || status == Status.CANNOT_RECEIVE) && server.checkCallLoad()) {
		    					state = States.OFF_HOOK;
		    					out.println("DialTone:0");
		    				} else if(status == Status.DEACTIVATED || status == Status.CANNOT_CALL) {
		    					state = States.NO_CALL;
		    					out.println("DialTone:1");
		    				} else {
		    					state = States.OFF_HOOK;
		    					out.println("DialTone:2");
		    				}
	    				} else if(state == States.RINGING) {
	    					server.addMessage(new PickUpTask(this, 5, null));
	    				}
	    			} else if(p[0].equals("OnHook")) {
	    				if(state == States.OFF_HOOK) {
	    					state = States.IDLE;
	    				} else if(state == States.NO_CALL) {
	    					state = States.IDLE;
	    				} else if(state == States.IN_CALL || state == States.WAITING) {
	    					server.addMessage(new HangUpTask(this, 4, null, server));
	    					state = States.IDLE;
	    				}
	    			} else if(p[0].equals("HWTestPassed")) {
	    				hwTest = true;
	    			} else if(p[0].equals("ResetState")) {
	    				break;
	    			}
		    	}
		    	
		    	if (!messageList.isEmpty()) {
		    		t = messageList.poll();
		    		
		    		t.ProcessTask();
		    		out.println(t.GetOutput());
		    		/*
		    		if (t.getType() == PhoneTask.Types.CALLER_RINGING){
		    			state = States.WAITING;
		    			outputLine = "CallerRinging";
		    		} else if (t.getType() == PhoneTask.Types.CALLEE_RINGING) {
		    			state = States.RINGING;
		    			outputLine = "CalleeRinging";
		    		} else if (t.getType() == PhoneTask.Types.START_CALL) {
		    			state = States.IN_CALL;
		    			outputLine = "StartCall:" + t.getData();
		    		} else if (t.getType() == PhoneTask.Types.END_CALL) {
		    			state = States.NO_CALL;
		    			outputLine = "EndCall";
		    		} else if (t.getType() == PhoneTask.Types.END_RINGING) {
		    			outputLine = "EndRinging";
		    			if(state == States.WAITING) {
		    				state = States.NO_CALL;
		    			} else if(state == States.RINGING) {
		    				state = States.IDLE;
		    			}
		    		} else if (t.getType() == PhoneTask.Types.CALL_FAILED) {
		    			outputLine = "CallFailed";
		    			state = States.NO_CALL;
		    		} else if (t.getType() == PhoneTask.Types.HW_TEST) {
		    			outputLine = "HWTest";
		    		} else if (t.getType() == PhoneTask.Types.RESET) {
		    			outputLine = "Reset";
		    		} else {
		    			outputLine = "";
		    		}
		    		
		    		out.println(outputLine);*/
		    	}
		    	

			}
		    out.close();
			in.close();
		    socket.close();

		} 
		catch (IOException e) {
			    e.printStackTrace();
		}
		finally
		{
			System.out.println("Phone disconnected");
		    server.removePhone(this);
		}
    }
    
    public synchronized void sendMessage(PhoneTask t) {
    	messageList.add(t);
    }
    
    public void setPhoneName(String name) {
    	phoneName = name;
    }
    
    public String getPhoneName() {
    	return phoneName;
    }
    
    public void setExtension(int extension) {
    	this.extension = extension;
    }
    
    public int getExtension() {
    	return extension;
    }
    
    public Status getPhoneStatus() {
    	return status;
    }
    
    public void setPhoneStatus(Status s) {
    	status = s;
    }
    
    public States getPhoneState() {
    	return state;
    }
    
    public Call getCurrentCall() {
    	return currentCall;
    }
    
    public void setCurrentCall(Call c) {
    	currentCall = c;
    }
    
    public void setPhoneState(States newState)
    {
    	state = newState;
    }
    
    public void disconnectPhone() throws IOException {
    	PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
    	out.println("Bye");
    	out.flush();
    	this.socket.close();
    }
    
    public boolean hardwareTest() {
    	
    	hwTest = false;
    	hwTestTimer = System.currentTimeMillis();

    	this.sendMessage(new HardwareTestTask(2, ""));
    	
    	while (!hwTest && ((System.currentTimeMillis() - hwTestTimer) < 5000)) {
    		try {
    			Thread.sleep(50);
    		} catch(Exception e) {
    			System.err.println("Error: Could not safely wait for 50 milliseconds");
    		}
    		
    	}
    	
    	return hwTest;
    }
    
}